#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <pthread.h>
#include "log.hpp"
#include "Socket.hpp"
#include "Protocol.hpp"

// using namespace protocol_ns;
using namespace protocol_ns_json;

class CalServer
{
    using func_t = std::function<Response(const Request &)>;

    struct ThreadData
    {
        ThreadData(int cfd, const std::string &cip, uint16_t cport, CalServer *ts)
            : _cfd(cfd), _cip(cip), _cport(cport), _ts(ts)
        {
        }

        int _cfd;
        std::string _cip;
        uint16_t _cport;
        CalServer *_ts;
    };

public:
    CalServer(func_t cb, uint16_t port) : _cb(cb), _port(port)
    {
    }
    ~CalServer()
    {
        _listensock.Close();
    }

    void Initial()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
    }

    void Start()
    {
        while (true)
        {
            std::string cln_ip;
            uint16_t cln_port;
            int cln_fd = _listensock.Accept(cln_ip, cln_port);
            if (cln_fd < 0)
                continue;

            // 与客户端交互的工作交给新线程
            pthread_t pid;
            pthread_create(&pid, nullptr, ThreadRountine, new ThreadData(cln_fd, cln_ip, cln_port, this));
        }
    }

private:
    void ServiceIO(int sockfd)
    {
        // package == "5\r\n1 + 2"
        std::string readBuf;
        while (true)
        {
            // 1.读取客户端发送的请求字符串(报头+有效载荷)
            std::string package;
            int n = ReadPackage(sockfd, readBuf, &package);
            if (n == -1)
                break;
            else if (n == 0) // 未读取完整package, 继续读取
                continue;

            std::cout << "package:\n"
                      << package << std::endl;
            // std::cout << "n=" << n << std::endl;

            // 2.解开报头, 提取有效载荷
            std::string body = RemoveHeader(package, n);

            std::cout << "body:\n"
                      << body << std::endl;

            // 3.将字符串有效载荷反序列化为Request对象
            Request req;
            req.Deserialize(body);

            // std::cout << req._x << std::endl;
            // std::cout << req._opt << std::endl;
            // std::cout << req._y << std::endl;

            // 4.业务处理
            Response resp = _cb(req);

            // 5.将响应序列化为字符串
            std::string outStr;
            resp.Serialize(&outStr);

            std::cout << "outStr:\n"
                      << outStr << std::endl;

            // 6.为响应添加报头
            AddHeader(outStr);

            std::cout << "outPackage:\n"
                      << outStr << std::endl;

            // 7.发送outStr到客户端
            n = send(sockfd, outStr.c_str(), outStr.size(), 0);
            if (n < 0)
            {
                LogMessage(FATAL, "send fail\n");
                break;
            }
        }
        close(sockfd);
    }

    static void *ThreadRountine(void *argv)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(argv);
        td->_ts->ServiceIO(td->_cfd);
        delete td;
    }

private:
    Sock _listensock;
    uint16_t _port;
    func_t _cb;
};
